grammar Expr;

tokens{
	PLUS 	='+';
	SUB	='-';
}

@header {
import com.priorbi.util.ObjectUtils;
import com.priorbi.report.script.ScriptContext;
}

@members {
	private ScriptContext scriptContext = ScriptContext.getInstance();
}

expr returns [Object value]
    :   
    	(
    		e=multExpr {$value = $e.value;}
        	(   PLUS e=multExpr {
        			$value=ObjectUtils.add($value,$e.value);
        		   }
        	|   '-' e=multExpr {
        			$value=ObjectUtils.sub($value,$e.value);
        		   }
        	|	PLUS  e=strValue{
        			$value = String.valueOf($value) + $e.value;
        		}
        	)*
        )
        |
        (
        	e=strValue{$value = $e.value;}
        	(
        		PLUS e=multExpr{
        			$value =$value + String.valueOf($e.value);
        		}
        		|
        		PLUS e=strValue{
        			$value =$value + String.valueOf($e.value);
        		}
        	)*
        )  
    ;

multExpr returns [Object value]
    :   e=atom {$value = $e.value;} 
    	(	
    		'*' e=atom {
    				$value=ObjectUtils.mult($value,$e.value);
    			    }
    	|	'/' e=atom {
    				$value=ObjectUtils.div($value,$e.value);
    			    }
    	)*
    ; 

/*function eval*/
func returns[Object value]
	:  FUNCNAME '(' 
		(	WS* {$value = scriptContext.getFuncValue($FUNCNAME.text, null);}
		|
			e=args{$value = scriptContext.getFuncValue($FUNCNAME.text, $e.value);}
		)
		')'
	;

/*Function args*/	
args returns [List<Object> value]
@init{
	$value = new ArrayList<Object>();
}
    	:	(e=expr {$value.add($e.value);})
    		(
    			',' (
    				e=strQuoted{$value.add($e.value);}
    				|
    				e=expr {$value.add($e.value);}
    			    )
    		)*
    	; 
    	
strValue returns [Object value]
	:    	StringLiteral {
			String v = $StringLiteral.text;
			$value = v.substring(1,v.length()-1);
		}
	;
	
strQuoted returns [Object value]
	:    	StringLiteral {
			$value = $StringLiteral.text;
		}
	;
    	
atom returns [Object value]
    	:   	NumberLiteral {$value = $NumberLiteral.text;}
   	|   	VAR {$value = scriptContext.getVariable($VAR.text);}
    	|   	func {$value = $func.value;}
    	|   	COLUMNROW {$value = scriptContext.getCellValue($COLUMNROW.text);}
    	|   	'(' expr ')' {$value = $expr.value;}
    	;
 	
fragment
Digit	:'0'..'9';

fragment
DigitNoZero 
	:	'1'..'9'
	;
    
fragment
HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
UnicodeEscape
    :   '\\' 'u' HexDigit HexDigit HexDigit HexDigit
    ;   


fragment
OctalEscape
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;
    
fragment
EscapeSequence
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UnicodeEscape
    |   OctalEscape
    ;
    
BooleanLiteral	:   'true'|'false';

StringLiteral
    :  '"' ( EscapeSequence | ~('\\'|'"') )* '"'
    ; 	
NumberLiteral 	:   '0.'Digit*|DigitNoZero Digit*|DigitNoZero Digit*'.'Digit*;
//Cell Element
COLUMNROW	: ('A'..'Z')+ DigitNoZero Digit*;
//function name
FUNCNAME	: ('a'..'z'|'_')('a'..'z'|'A'..'Z'|'_')+Digit*;
//var
VAR		: '$'('a'..'z'|'A'..'Z')+Digit*;
//number
//NUMBER 		:   '0.'Digit*|DigitNoZero Digit*|DigitNoZero Digit*'.'Digit*;
//white space
WS  		:   (' '|'\t')+ {skip();};